/////////////////////////////////////////////////////////////////////////////
// This file is part of the "Java-DAP" project, a Java implementation
// of the OPeNDAP Data Access Protocol.
//
// Copyright (c) 2007 OPeNDAP, Inc.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
/////////////////////////////////////////////////////////////////////////////
using System;
using System.Collections;
using System.IO;
using System.Text;
using AvalonTech.Conversion;
using AvalonTech.IO;
using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
using NDODS.DAP.BaseTypes;
using NDODS.DAP.Exceptions;

namespace NDODS.DAP
{
    /// <summary> The DataDDS class extends DDS to add new methods for retrieving data from
    /// the server, and printing out the contents of the data.
    /// 
    /// </summary>
    /// <author>  jehamby
    /// </author>
    /// <version>  $Revision: 15901 $
    /// </version>
    /// <seealso cref="DDS">
    /// </seealso>
    [Serializable]
    public class DataDDS : DDS
    {
        /// <summary> Returns the <code>ServerVersion</code> given in the constructor.
        /// 
        /// </summary>
        /// <returns> the <code>ServerVersion</code> given in the constructor.
        /// </returns>
        public virtual ServerVersion ServerVersion
        {
            get { return ver; }
        }

        /// <summary> The ServerVersion returned from the open OPeNDAP connection.</summary>
        private ServerVersion ver;

        /// <summary> Construct the DataDDS with the given server version.
        /// 
        /// </summary>
        /// <param name="ver">the ServerVersion returned from the open OPeNDAP connection.
        /// </param>
        public DataDDS(ServerVersion ver) 
        {
            this.ver = ver;
        }

        public DataDDS(ServerVersion ver, IBaseTypeFactory btf) : base(btf)
        {
            this.ver = ver;
        }

        /// <summary> IsRead the data stream from the given InputStream.  In the C++ version,
        /// this code was in Connect.
        /// 
        /// </summary>
        /// <param name="is_Renamed">      the InputStream to Read from
        /// </param>
        /// <param name="statusUI">the StatusUI object to use, or null
        /// </param>
        /// <throws>  EOFException      if EOF is found before the variable is completely </throws>
        /// <summary>                           deserialized.
        /// </summary>
        /// <throws>  IOException       thrown on any other InputStream exception. </throws>
        /// <throws>  DataReadException when invalid data is Read, or if the user </throws>
        /// <summary>                           cancels the download.
        /// </summary>
        /// <throws>  DAP2Exception     if the OPeNDAP server returned an error. </throws>
        public virtual void ReadData(Stream is_Renamed, IStatusUI statusUI)
        {
            // Buffer the input stream for better performance
            BufferedStream bufferedIS = new BufferedStream(is_Renamed);
            // Use a DataInputStream for Deserialize
            //UPGRADE_TODO: Class 'java.io.DataInputStream' was converted to 'System.IO.BinaryReader' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javaioDataInputStream'"
            //BinaryReader dataIS = new BinaryReader(bufferedIS);
            EndianBinaryReader dataIS = new EndianBinaryReader(new BigEndianBitConverter(), bufferedIS);


            //UPGRADE_TODO: Method 'java.util.Enumeration.hasMoreElements' was converted to 'System.Collections.IEnumerator.MoveNext' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilEnumerationhasMoreElements'"
            for (IEnumerator e = Variables; e.MoveNext();)
            {
                if (statusUI != null && statusUI.UserCancelled())
                    throw new DataReadException("User cancelled");
                //UPGRADE_TODO: Method 'java.util.Enumeration.nextElement' was converted to 'System.Collections.IEnumerator.Current' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilEnumerationnextElement'"
                IClientIO bt = (IClientIO) e.Current;
                //System.out.println("Deserializing: "+((BaseType)bt).getTypeName()+" "+((BaseType)bt).getName());
                bt.Deserialize(dataIS, ver, statusUI);
            }
            // notify GUI of Finished download
            if (statusUI != null)
                statusUI.Finished();
        }

        /// <summary> Print the dataset just Read.  In the C++ version, this code was in
        /// <code>geturl</code>.
        /// 
        /// </summary>
        /// <param name="pw">the <code>StreamWriter</code> to use.
        /// </param>
        public virtual void PrintValue(StreamWriter pw)
        {
            //UPGRADE_TODO: Method 'java.util.Enumeration.hasMoreElements' was converted to 'System.Collections.IEnumerator.MoveNext' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilEnumerationhasMoreElements'"
            for (IEnumerator e = Variables; e.MoveNext();)
            {
                //UPGRADE_TODO: Method 'java.util.Enumeration.nextElement' was converted to 'System.Collections.IEnumerator.Current' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilEnumerationnextElement'"
                BaseType bt = (BaseType) e.Current;
                bt.PrintValue(pw, "", true);
                pw.Flush();
            }
            //UPGRADE_TODO: Method 'java.io.StreamWriter.println' was converted to 'System.IO.TextWriter.WriteLine' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javaioStreamWriterprintln'"
            pw.WriteLine();
        }

        /// <summary> Print the dataset using OutputStream.
        /// 
        /// </summary>
        /// <param name="os">the <code>OutputStream</code> to use.
        /// </param>
        public void PrintValue(Stream os)
        {
            //UPGRADE_WARNING: At least one expression was used more than once in the target code. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1181'"
            StreamWriter pw = new StreamWriter(os, Encoding.Default);
            PrintValue(pw);
            pw.Flush();
        }

        /// <summary> Dump the dataset using Externalize methods. This should create
        /// a multipart Mime document with the binary representation of the
        /// DDS that is currently in memory.
        /// 
        /// </summary>
        /// <param name="os">      the <code>OutputStream</code> to use.
        /// </param>
        /// <param name="compress"><code>true</code> if we should compress the output.
        /// </param>
        /// <param name="headers"> <code>true</code> if we should Print HTTP headers.
        /// </param>
        /// <throws>  IOException thrown on any <code>OutputStream</code> exception. </throws>
        public void Externalize(Stream os, bool compress, bool headers)
        {
            // First, Print headers
            if (headers)
            {
                //UPGRADE_WARNING: At least one expression was used more than once in the target code. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1181'"
                StreamWriter pw = new StreamWriter(os, Encoding.Default);
                //UPGRADE_TODO: Method 'java.io.StreamWriter.println' was converted to 'System.IO.TextWriter.WriteLine' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javaioStreamWriterprintln_javalangString'"
                pw.WriteLine("HTTP/1.0 200 OK");
                //UPGRADE_TODO: Method 'java.io.StreamWriter.println' was converted to 'System.IO.TextWriter.WriteLine' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javaioStreamWriterprintln_javalangString'"
                pw.WriteLine("Server: " + ServerVersion.CurrentVersion);
                //UPGRADE_TODO: Method 'java.io.StreamWriter.println' was converted to 'System.IO.TextWriter.WriteLine' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javaioStreamWriterprintln_javalangString'"
                pw.WriteLine("Content-type: application/octet-stream");
                //UPGRADE_TODO: Method 'java.io.StreamWriter.println' was converted to 'System.IO.TextWriter.WriteLine' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javaioStreamWriterprintln_javalangString'"
                pw.WriteLine("Content-Description: dods_data");
                if (compress)
                {
                    //UPGRADE_TODO: Method 'java.io.StreamWriter.println' was converted to 'System.IO.TextWriter.WriteLine' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javaioStreamWriterprintln_javalangString'"
                    pw.WriteLine("Content-Encoding: deflate");
                }
                //UPGRADE_TODO: Method 'java.io.StreamWriter.println' was converted to 'System.IO.TextWriter.WriteLine' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javaioStreamWriterprintln'"
                pw.WriteLine();
                pw.Flush();
            }

            // Buffer the output stream for better performance
            Stream bufferedOS;
            if (compress)
            {
                // deflate has its own buffering
                //UPGRADE_ISSUE: Constructor 'java.util.zip.DeflaterOutputStream.DeflaterOutputStream' was not converted. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1000_javautilzipDeflaterOutputStream'"
                bufferedOS = new DeflaterOutputStream(os);
            }
            else
            {
                bufferedOS = new BufferedStream(os);
            }

            // Redefine StreamWriter here, so the DDS is also compressed if necessary
            //UPGRADE_WARNING: At least one expression was used more than once in the target code. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1181'"
            StreamWriter pw2 = new StreamWriter(bufferedOS, Encoding.Default);
            Print(pw2);
            // pw.println("Data:");  // JCARON CHANGED
            pw2.Flush();
            sbyte[] temp_sbyteArray;
            temp_sbyteArray = SupportClass.ToSByteArray(SupportClass.ToByteArray("\nData:\n"));
            bufferedOS.Write(SupportClass.ToByteArray(temp_sbyteArray), 0, temp_sbyteArray.Length); // JCARON CHANGED
            bufferedOS.Flush();

            // Use a DataOutputStream for serialize
            //UPGRADE_TODO: Class 'java.io.DataOutputStream' was converted to 'System.IO.BinaryWriter' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javaioDataOutputStream'"
            BinaryWriter dataOS = new BinaryWriter(bufferedOS);
            //UPGRADE_TODO: Method 'java.util.Enumeration.hasMoreElements' was converted to 'System.Collections.IEnumerator.MoveNext' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilEnumerationhasMoreElements'"
            for (IEnumerator e = Variables; e.MoveNext();)
            {
                //UPGRADE_TODO: Method 'java.util.Enumeration.nextElement' was converted to 'System.Collections.IEnumerator.Current' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilEnumerationnextElement'"
                IClientIO bt = (IClientIO) e.Current;
                bt.Externalize(dataOS);
            }
            // Note: for DeflaterOutputStream, flush() is not sufficient to flush
            // all buffered data
            dataOS.Close();
        }
    }
}